﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Text;

namespace RB.Utility
{
    internal class ClassCopier<T>
    {
        interface IMemberAccessor
        {
            void Copy(object source, object target);
        }

        class MemberAccessor<P> : IMemberAccessor
        {
            private Func<T, P> GetValueDelegate;
            private Action<T, P> SetValueDelegate;

            public MemberAccessor(PropertyInfo propertyInfo)
            {
                Debug.Assert(propertyInfo != null);

                GetValueDelegate = (Func<T, P>)Delegate.CreateDelegate(typeof(Func<T, P>), propertyInfo.GetGetMethod());
                SetValueDelegate = (Action<T, P>)Delegate.CreateDelegate(typeof(Action<T, P>), propertyInfo.GetSetMethod());
            }

            public void Copy(object source, object target)
            {
                SetValueDelegate((T)target, GetValueDelegate((T)source));
            }
        }

        private static List<IMemberAccessor> _memberAccessors;

        static ClassCopier()
        {
            _memberAccessors = new List<IMemberAccessor>();

            var propertyInfos = typeof(T).GetPublicProperties();
            foreach (PropertyInfo info in propertyInfos)
            {
                if (info.CanRead && info.CanWrite)
                {
                    Type accessorType = typeof(MemberAccessor<>).MakeGenericType(typeof(T), info.PropertyType);
                    var accessor = (IMemberAccessor)Activator.CreateInstance(accessorType, info);
                    _memberAccessors.Add(accessor);
                }
            }
        }

        internal static void Copy(T source, T target)
        {
            foreach(var accessor in _memberAccessors)
            {
                accessor.Copy(source, target);
            }
        }
    }
}
